/*
 * File:   Box2dBody.cpp
 * Author: Elevator
 *
 * Created on 24 Май 2013 г., 21:36
 */

#include "IBody.h"
#include "Box2dBody.h"
#include <Box2D/Box2D.h>

namespace physics {

	Box2dBody::Box2dBody( b2Body* body ) :
	_body( body ) {
	}

	Box2dBody::~Box2dBody( ) {
	}

	void Box2dBody::SetVel( const Transform& vel ) {
		b2Vec2 vec = b2Vec2( vel.Vec.X, vel.Vec.Y );
		_body->SetLinearVelocity( vec );
		_body->SetAngularVelocity( vel.Rot );
	}

	Transform Box2dBody::GetVel( ) const {
		b2Vec2 vec = _body->GetLinearVelocity( );
		float rot = _body->GetAngularVelocity( );
		return Transform( Vec2( vec.x, vec.y ), rot );
	}

	void Box2dBody::SetPos( const Transform& pos ) {
		b2Vec2 vec = b2Vec2( pos.Vec.X, pos.Vec.Y );
		_body->SetTransform( vec, pos.Rot );
	}

	Transform Box2dBody::GetPos( ) const {
		b2Transform transform = _body->GetTransform( );
		b2Vec2 vec = transform.position;
		float rot = -transform.GetAngle( );
		return Transform( Vec2( vec.x, vec.y ), rot );
	}

	float Box2dBody::GetMass( ) const {
		return _body->GetMass( );
	}

	void Box2dBody::SetMass( float mass ) {
		b2MassData* massData = 0;
		_body->GetMassData( massData );
		massData->mass = mass;
		_body->SetMassData( massData );
	}

	float Box2dBody::GetInertia( ) const {
		return _body->GetInertia( );
	}

	void Box2dBody::SetInertia( float inertia ) {
		b2MassData* massData = 0;
		_body->GetMassData( massData );
		massData->I = inertia;
		_body->SetMassData( massData );
	}

	IBody::Type Box2dBody::GetType( ) const {
		switch( _body->GetType( ) ) {
			case b2_dynamicBody: return Dynamic;
			case b2_staticBody: return Static;
			case b2_kinematicBody: return Kinematic;
			default: return Dynamic;
		}
	}

	void Box2dBody::SetType( IBody::Type value ) {
		switch( value ) {
			case Dynamic: _body->SetType( b2_dynamicBody );
				break;
			case Static: _body->SetType( b2_staticBody );
				break;
			case Kinematic: _body->SetType( b2_kinematicBody );
				break;
		}
	}

	IIterable<const ICollider*>* Box2dBody::GetColliders( ) const {
		return (IIterable<const ICollider*>* )( &_colliders );
	}

	ICollider* Box2dBody::CreateCollider( float friction, float restitution, const IShape* shape ) {
		b2FixtureDef fixtureDef;
		//	Box2dShape* box2dShape = (Box2dShape*) shape;
		const Box2dShape* box2dShape = dynamic_cast<const Box2dShape*> ( shape );

		fixtureDef.shape = box2dShape->GetBox2dShape( );
		fixtureDef.friction = friction;
		fixtureDef.restitution = restitution;
		b2Fixture* fixture = _body->CreateFixture( &fixtureDef );
		Box2dCollider* collider = new Box2dCollider( fixture );
		collider->SetShape(shape);
		_colliders.Add( collider );
		return collider;
	}

	void Box2dBody::DestroyCollider( ICollider* collider ) {
		//	Box2dCollider* box2dCollider = (Box2dCollider*) collider;
		Box2dCollider* box2dCollider = dynamic_cast<Box2dCollider*> ( collider );

		_colliders.Remove( box2dCollider );
		_body->DestroyFixture( box2dCollider->GetBox2dFixture( ) );
	}

	b2Body* Box2dBody::GetBox2dBody( ) {
		return _body;
	}
}
